//
//  OIEmulatorWindowController.m
//  OrchIDE
//
//  Created by local22 on 8/13/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "OIEmulatorWindowController.h"
#import "OIEmulator.h"
#import "OIMemoryWindowController.h"
#import "OISerialConsoleWindowController.h"

int OIEmulatorWindowControllerObservationContextRegisterValues = 101;

@implementation OIEmulatorWindowController
- (id)initWithWindow:(NSWindow *)window
{
	self = [super initWithWindow:window];
	if(!self) {
		return nil;
	}
	
	[self setShouldCloseDocument:YES];
	_stepTimerInterval = 1.0/100.0;
	
	return self;
}

- (void)dealloc
{
	if(_stepTimer) {
		[_stepTimer invalidate];
		_stepTimer = nil;
	}
	
	[self setEmulator:nil];
	
	[super dealloc];
}

- (NSString *)windowNibName
{
	return @"OIEmulator";
}

- (void)windowDidLoad
{
	[_tableView setDoubleAction:@selector(openMemoryWindowAtAddress:)];
}

- (BOOL)validateToolbarItem:(NSToolbarItem *)item
{
	if([item action] == @selector(transport:)) {
		NSSegmentedControl *transport = (NSSegmentedControl *)[item view];
		if(_stepTimer) {
			[item setLabel:@"Stop"];
			[[transport cell] setTrackingMode:NSSegmentSwitchTrackingSelectAny];	
			[transport setEnabled:NO forSegment:0];
			[transport setSelected:YES forSegment:1];
			[transport setEnabled:NO forSegment:2];
		} else {
			[item setLabel:@"Start"];
			[[transport cell] setTrackingMode:NSSegmentSwitchTrackingMomentary];
			[transport setEnabled:[_emulator canUnstep] forSegment:0];
			[transport setSelected:NO forSegment:1];
			[transport setEnabled:YES forSegment:2];
		}
	}
	
	return YES;
}

#pragma mark Accessors
- (void)setEmulator:(OIEmulator *)emulator
{
	if(emulator == _emulator) {
		return;
	}
	
	NSArray *observedKeyPaths = [NSArray arrayWithObjects:@"r0", @"r1", @"r2", @"r3", @"r4", @"r5", @"r6", @"r7", @"executing", @"flag", @"userMode", @"rSerial", @"instruction", @"exceptionState", nil];
	for(NSString *keyPath in observedKeyPaths) {
		[_emulator removeObserver:self forKeyPath:keyPath];
	}
	
	[_emulator release];
	_emulator = [emulator retain];
	
	for(NSString *keyPath in observedKeyPaths) {
		[_emulator addObserver:self forKeyPath:keyPath options:0 context:(void *)&OIEmulatorWindowControllerObservationContextRegisterValues];
	}
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
	if(context == &OIEmulatorWindowControllerObservationContextRegisterValues) {
		[_tableView reloadData];
	}
}


#pragma mark Actions
- (IBAction)stepForward:(id)sender
{
	[_emulator step];
}

- (IBAction)stepBackward:(id)sender
{
	[_emulator unstep];
}

- (void)continuousStepTimer:(NSTimer *)timer
{
	[_emulator stepCycles:1001];
}

- (IBAction)toggleContinuousStep:(id)sender
{
	if(_stepTimer) {
		[_stepTimer invalidate];
		_stepTimer = nil;
	} else {
		_stepTimer = [NSTimer scheduledTimerWithTimeInterval:_stepTimerInterval target:self selector:@selector(continuousStepTimer:) userInfo:nil repeats:YES];
	}
}

- (IBAction)bigRedButton:(id)sender
{
	[_emulator bigRedButton];
}

- (IBAction)transport:(id)sender
{
	SEL action = nil;
	switch([sender selectedSegment]) {
		case 0:
			action = @selector(stepBackward:);
			break;
		case 1:
			action = @selector(toggleContinuousStep:);
			break;
		case 2:
			action = @selector(stepForward:);
			break;
	}
	
	[self doCommandBySelector:action];
}

- (IBAction)openMemoryWindowAtAddress:(id)sender
{
	int selectedRow = [sender selectedRow];
	if(selectedRow == -1) {
		return;
	} else if(!NSLocationInRange(selectedRow, NSMakeRange(1, 8))) {
		NSBeep();
		return;
	}
	
	int32_t address = [[_emulator valueForKey:[NSString stringWithFormat:@"r%d", selectedRow - 1]] intValue];
	
	OIMemoryWindowController *memoryWindowController = [[OIMemoryWindowController alloc] init];
	[memoryWindowController setTrackingRegister:[NSString stringWithFormat:@"r%d", selectedRow - 1]];
	[memoryWindowController setEmulator:_emulator];
	[memoryWindowController scrollToAddress:address];
	[[self document] addWindowController:memoryWindowController];
	[memoryWindowController showWindow:nil];
	[memoryWindowController release];
}

- (IBAction)openMemoryWindow:(id)sender
{
	OIMemoryWindowController *memoryWindowController = [[OIMemoryWindowController alloc] init];
	[memoryWindowController setEmulator:_emulator];
	[[self document] addWindowController:memoryWindowController];
	[memoryWindowController showWindow:nil];
	[memoryWindowController release];
}

- (IBAction)showSerialConsole:(id)sender
{
	if(!_serialConsoleController) {
		_serialConsoleController = [[OISerialConsoleWindowController alloc] init];
		[_serialConsoleController setEmulator:_emulator];
		[[self document] addWindowController:_serialConsoleController];
	}
	
	[_serialConsoleController showWindow:nil];
}

#pragma mark Table view data source
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
	return 16;
}
- (NSString *)tableView:(NSTableView *)tableView keyForRow:(NSInteger)row
{
	id key = nil;
	switch(row) {
		case 0:
			key = @"Registers";
			break;
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
			key = [NSString stringWithFormat:@"r%d", row - 1];
			break;
		case 9:
			key = @"State";
			break;
		case 10:
			key = @"executing";
			break;
		case 11:
			key = @"flag";
			break;
		case 12:
			key = @"userMode";
			break;
		case 13:
			key = @"rSerial";
			break;
		case 14:
			key = @"instruction";
			break;
		case 15:
			key = @"exceptionState";
			break;
	}
	return key;
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row;
{
	id key = [self tableView:tableView keyForRow:row];
	
	if([[tableColumn identifier] isEqualToString:@"Key"]) {
		return key;
	} else if([self tableView:tableView isGroupRow:row]) {
		return nil;
	} else {
		return [_emulator valueForKey:key];
	}

}

- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
	if([self tableView:tableView isGroupRow:row]) {
		return;
	}
	
	id key = [self tableView:tableView keyForRow:row];
	[_emulator setValue:object forKey:key];
}

- (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row;
{
	return (row == 0 || row == 9);
}

- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
{
	return ![self tableView:tableView isGroupRow:row];
}

- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
	if([[tableColumn identifier] isEqualToString:@"Value"]) {
		if(NSLocationInRange(row, NSMakeRange(10, 3))) {
			NSButtonCell *checkbox = [[NSButtonCell alloc] initTextCell:@""];
			[checkbox setButtonType:NSSwitchButton];
			if(row == 12) {
				[checkbox setEnabled:[_emulator isExecuting]];
			}
			return [checkbox autorelease];
		} else {
			return [tableColumn dataCellForRow:row];
		}
	} else {
		return [tableColumn dataCellForRow:row];
	}

}
@end
